/**
 * 断言
 * 告诉TS或提示自己数据的类型
*/

// 类型断言
let a: any = 'string';
let b: number = (<string>a).length
// let b:number = a.length 这样也可以运行，但是不会提示length
let c: number = (a as string).length
console.log(b)

// 非空断言
/**
 * 1. 忽略null和undefined类型
*/
function f1(arg: undefined | null | number) {
    /* let temp:number = arg; 
    报错：
      Type 'string | number | boolean' is not assignable to type 'number'.
      Type 'string' is not assignable to type 'number'.
    */
    let ignoreNullandUndefined: number = arg!; // 意思是忽略null 和 undefined,告诉TS我不是null和undefined

}

/**
 * 2. 调用函数时忽略参数的undefined类型
*/
type fn = () => number;
function f2(arg: undefined | fn) {
    arg();
    const f1 = arg();
}
type NumGenerator = () => number;
function myFunc(numGenerator: NumGenerator | undefined) {
    const num1 = numGenerator(); // 会报错？
    const num2 = numGenerator!(); // 不会报错
}

// 确定赋值断言
let d!: number; // 一个声明后未赋值的变量,但是加上断言告诉TS之后会赋值
add();
console.log(2 * d);
function add() {
    d = 1 + 1;
}

// 联合类型, union是类型的别名
type union = string | number | boolean ;
let e:union = 's';
e = 1;
e = true;

/**
 * 交叉类型 (合并)多个类型合并成一个类型
*/
type a = { a:number }
type b = a & { b:number }
let f:b = { // f这样赋值才可以
    a:1,
    b:1
}

// 当联合的类型中有冲突，基本数据类型
type c = { a:number }
type d = c & { a:string }
/* let g:d = {
    a:1 或 a:'s'
    Type 'number'/'string' is not assignable to type 'never'.
    因为a既是string 类型又是 number 类型，这是一个不可能的类型，所以最终三十never类型
} */

// 有冲突，但是是非基本数据类型
type AA = { d:string }
type BB = { e:number }
type CC = { f:boolean }

type A = { a:AA }
type B = { a:BB }
type C = { a:CC }

type ABC = A & B & C;
let aa:ABC = { // 实际上没有发生基本数据类型的冲突
    a:{
        d:'s',
        e:1,
        f:true
    }
}